package com.cyf.pay.alipay.service.impl;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.domain.AlipayTradePrecreateModel;
import com.alipay.api.domain.AlipayTradeQueryModel;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.request.AlipayTradePrecreateRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.cyf.db.bean.ad.AdPayOrder;
import com.cyf.db.bean.PayOrder;
import com.cyf.db.mapper.ad.AdPayOrderMapper;
import com.cyf.db.mapper.PayOrderMapper;
import com.cyf.pay.alipay.service.AlipayService;
import com.cyf.service.AdPayOrderService;
import com.cyf.util.AlipayConfig;
import com.cyf.util.PayOrderMessageList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.Map;

/**
 * 支付宝支付
 * Created by cage on 2017/2/27.
 */
@Service
public class AlipayServiceImpl implements AlipayService {

    private static final Logger logger = LoggerFactory.getLogger(AlipayServiceImpl.class);

    private static final SimpleDateFormat GMT_PAYMENT_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private static final SimpleDateFormat OUTTIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Autowired
    private PayOrderMapper payOrderMapper;
    @Autowired
    private AdPayOrderMapper adPayOrderMapper;
    @Autowired
    private AdPayOrderService adPayOrderService;

    @Override
    public AlipayTradeAppPayResponse unifiedOrder(AlipayTradeAppPayModel model) {
        //实例化客户端
        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.UNIFIEDORDER_URL, AlipayConfig.APP_ID, AlipayConfig.APP_PRIVATE_KEY, "json", AlipayConfig.CHARSET, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.SIGN_TYPE);
        //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称：alipay.trade.app.pay
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
        //SDK已经封装掉了公共参数，这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
        model.setTimeoutExpress(AlipayConfig.TIMEOUT_EXPRESS);
        model.setProductCode(AlipayConfig.PRODUCT_CODE);
//        model.setSellerId(AlipayConfig.SELLER_ID);
        request.setBizModel(model);
        request.setNotifyUrl(AlipayConfig.NOTIFY_URL);
        try {
            //这里和普通的接口调用不同，使用的是sdkExecute
            AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
            if (response == null) {
                response = new AlipayTradeAppPayResponse();
                response.setSubCode("fail");
            }
            return response;
        } catch (AlipayApiException e) {
            e.printStackTrace();
            AlipayTradeAppPayResponse response = new AlipayTradeAppPayResponse();
            response.setSubCode("fail");
            return response;
        }
    }

    @Override
    public String payNotify(Map<String, String> params) {
        // 3、校验通知中的seller_id（或者seller_email) 是否为out_trade_no这笔单据的对应的操作方（有的时候，一个商户可能有多个seller_id/seller_email）
        // 4、验证app_id是否为该商户本身
        String appId = params.get("app_id");
        if (!AlipayConfig.APP_ID.equals(appId)) {
            logger.info("app_id错误");
            return AlipayConfig.NOTIFY_RETURN_FAIL;
        }

        String subject = params.get("subject");
        if ("支付广告费".equals(subject)) {
            return payNotifyForAdFee(params);
        } else {
            return payNotifyForParkingFee(params);
        }
    }
    private String payNotifyForAdFee(Map<String, String> params) {
        try {
            // 1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号
            String orderNo = params.get("out_trade_no");
            AdPayOrder adPayOrder = adPayOrderMapper.getByOrderNo(orderNo);
            if (adPayOrder == null) {
                logger.info("商户订单号错误");
                return AlipayConfig.NOTIFY_RETURN_FAIL;
            }
            // 2、判断total_fee是否确实为该订单的实际金额（即商户订单创建时的金额）
            String totalAmount = params.get("receipt_amount");
            if (Double.parseDouble(totalAmount) != adPayOrder.getTxnAmt() * 0.01) {
                logger.info("实际金额错误");
                return AlipayConfig.NOTIFY_RETURN_FAIL;
            }

            if (AdPayOrder.STATUS_WAIT_PAY != adPayOrder.getStatus()) {
                logger.info("该订单已经处理过，不再处理！订单状态：{}", adPayOrder.getStatus());
                return "success";
            } else {
                // 交易通知状态为TRADE_SUCCESS或TRADE_FINISHED时，支付宝才会认定为买家付款成功
                int payStatus = PayOrder.PAY_FAIL;
                String tradeStatus = params.get("trade_status");
                if ("WAIT_BUYER_PAY".equals(tradeStatus)) {
                    return AlipayConfig.NOTIFY_RETURN_FAIL;
                }
                if (!("TRADE_SUCCESS".equals(tradeStatus) || "TRADE_FINISHED".equals(tradeStatus))) {   // 支付失败
                    logger.info("支付失败");
                    //adPayOrderService.payFinish(adPayOrder, AdPayOrder.STATUS_WAIT_PAY, params.get("trade_no"), (int) (Double.parseDouble(totalAmount) * 100), null);
                    return "success";
                }
                logger.info("支付成功");
                String payTimeStr = params.get("gmt_payment");  // 该笔交易的买家付款时间。格式为yyyy-MM-dd HH:mm:ss
                adPayOrderService.payFinish(adPayOrder, AdPayOrder.STATUS_WAIT_REVIEW, params.get("trade_no"), (int) (Double.parseDouble(totalAmount) * 100), GMT_PAYMENT_FORMAT.parse(payTimeStr));
                return "success";
            }
        } catch (Exception e) {
            logger.error("处理APP支付宝支付异步通知异常：{}", e);
            return AlipayConfig.NOTIFY_RETURN_FAIL;
        }
    }

    private String payNotifyForParkingFee(Map<String, String> params) {
        try {
            // 1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号
            String orderNo = params.get("out_trade_no");
            PayOrder payOrder = payOrderMapper.getByOrderNo(orderNo);
            if (payOrder == null) {
                logger.info("商户订单号错误");
                return AlipayConfig.NOTIFY_RETURN_FAIL;
            }
            // 2、判断total_fee是否确实为该订单的实际金额（即商户订单创建时的金额）
            String totalAmount = params.get("total_amount");
            if (Double.parseDouble(totalAmount) != payOrder.getFee() * 0.01) {
                logger.info("实际金额错误");
                return AlipayConfig.NOTIFY_RETURN_FAIL;
            }

            if (PayOrder.PAY_UNKNOWN != payOrder.getPayStatus()) {
                logger.info("该订单已经处理过，不再处理！");
                return "success";
            } else {
                // 交易通知状态为TRADE_SUCCESS或TRADE_FINISHED时，支付宝才会认定为买家付款成功
                int payStatus = PayOrder.PAY_FAIL;
                String tradeStatus = params.get("trade_status");
                if ("WAIT_BUYER_PAY".equals(tradeStatus)) {
                    return AlipayConfig.NOTIFY_RETURN_FAIL;
                }
                if (!("TRADE_SUCCESS".equals(tradeStatus) || "TRADE_FINISHED".equals(tradeStatus))) {   // 支付失败
                    logger.info("支付失败");
                    payOrder.setTransactionId(params.get("trade_no"));
                    payOrder.setPayStatus(payStatus);
                    payOrder.setActualFee(0);
                    payOrderMapper.updatePayOrder(payOrder);
                    return "success";
                }
                logger.info("支付成功");
                String payTimeStr = params.get("gmt_payment");  // 该笔交易的买家付款时间。格式为yyyy-MM-dd HH:mm:ss

                // 支付成功，更新支付账单。
                payStatus = PayOrder.PAY_SUCCESS;
                payOrder.setTransactionId(params.get("trade_no"));
                payOrder.setPayStatus(payStatus);
                payOrder.setPayTime(GMT_PAYMENT_FORMAT.parse(payTimeStr));
                payOrder.setActualFee(payOrder.getFee());
                payOrderMapper.updatePayOrder(payOrder);

                if (1 == payOrder.getFeeType() || 2 == payOrder.getFeeType()) { // 是支付停车费
                    logger.info("支付成功消息添加到消息队列中！");
                    // 将支付消息添加到消息队列中
                    PayOrderMessageList.addPayOrderMessage(payOrder);
                }
                return "success";
            }
        } catch (Exception e) {
            logger.error("处理APP支付宝支付异步通知异常：{}", e);
            return AlipayConfig.NOTIFY_RETURN_FAIL;
        }
    }

    @Override
    public AlipayTradeQueryResponse queryOrder(AlipayTradeQueryModel model) {
        //实例化客户端
        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.QUERYORDER_URL, AlipayConfig.APP_ID, AlipayConfig.APP_PRIVATE_KEY, "json", AlipayConfig.CHARSET, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.SIGN_TYPE);

        //实例化具体API对应的request类
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        request.setBizModel(model);
        try {
            AlipayTradeQueryResponse response = alipayClient.execute(request);
            if (response == null) {
                response = new AlipayTradeQueryResponse();
                response.setSubCode("fail");
            }
            return response;
        } catch (AlipayApiException e) {
            e.printStackTrace();
            AlipayTradeQueryResponse response = new AlipayTradeQueryResponse();
            response.setSubCode("fail");
            return response;
        }
    }

    @Override
    public AlipayTradePrecreateResponse getQrcode(String orderNo, String fee, String subject) {
        //实例化客户端
        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.UNIFIEDORDER_URL, AlipayConfig.APP_ID, AlipayConfig.APP_PRIVATE_KEY, "json", AlipayConfig.CHARSET, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.SIGN_TYPE);
        AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();//创建API对应的request类
        //SDK已经封装掉了公共参数，这里只需要传入业务参数
        AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
        model.setOutTradeNo(orderNo);
        model.setTotalAmount(fee);
        model.setSubject(subject);
        model.setTimeoutExpress(AlipayConfig.TIMEOUT_EXPRESS);
//
        request.setBizModel(model);
        request.setNotifyUrl(AlipayConfig.NOTIFY_URL);
        try {
            AlipayTradePrecreateResponse response = alipayClient.execute(request);
            if (response == null) {
                response = new AlipayTradePrecreateResponse();
                response.setSubCode("fail");
            }
            return response;
        } catch (AlipayApiException e) {
            e.printStackTrace();
            AlipayTradePrecreateResponse response = new AlipayTradePrecreateResponse();
            response.setSubCode("fail");
            return response;
        }
    }
}
